package fellowship;

import java.awt.Button;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import terrain.Terrain;
import equipment.Armor;
import equipment.ElfBow;
import equipment.ElvenCloak;
import main.Army;
import main.Equipment;
import main.Game;
import main.Hero;
import main.ShootUI;
import main.UI;
import main.Unit;
import main.Utils;

public class Legolas extends Hero {
	public Equipment[] equipChoices = {new ElvenCloak(), new Armor()};
	int shotsFired = 0;
	
	public Legolas(int id, int armyIndex, int x, int y) {
		this.strength = 4;
		this.defense = 4;
		this.attacks = 2;
		this.wounds = 2;
		this.courage = 6;
		this.fightValue = 6;
		this.shootValue = 3;
		
		this.might = 3;
		this.will = 2;
		this.fate = 3;
		this.initWorking();

		this.baseMove = 6.0;
		this.move = 6.0;
		this.moveLeft = 6.0;
		
		this.id = id;
		this.name = "Legolas";
		this.race = "Elf";
		this.x = x;
		this.y = y;
		this.armyIndex = armyIndex;
		
		this.equip(new ElfBow());
	}
	
	// Currently only supports cloning at beginning of game (missing some variables that can change throughout game)
	public Legolas clone() {
		Legolas copy = new Legolas(this.id, this.armyIndex, this.x, this.y);
		copy.strength = this.strength;
		copy.defense = this.defense;
		copy.attacks = this.attacks;
		copy.wounds = this.wounds;
		copy.courage = this.courage;
		copy.fightValue = this.fightValue;
		copy.shootValue = this.shootValue;
				
		copy.move = this.move;
		copy.moveLeft = this.moveLeft;
		copy.shootRange = this.shootRange;
		copy.shootStrength = this.shootStrength;
		copy.moveNeededToShoot = this.moveNeededToShoot;
		copy.hasShot = this.hasShot;
		
		copy.equipmentList = new ArrayList<Equipment>();
		for(Equipment e : this.equipmentList){
			copy.equipmentList.add(e);
		}
		
		copy.supporters = new ArrayList<Unit>();
		for(Unit u : this.supporters){
			copy.supporters.add(u);
		}
		
		copy.battle = this.battle;
		copy.game = this.game;
		
		return copy;
	}

	public Equipment[] getEquipChoices() {
		return this.equipChoices;
	}
	
	// Updated to reflect Legolas' Deadly Shot rule.
	public void refresh(){
		if (!layingDown)
			this.moveLeft = this.move;
		else
			this.moveLeft = 1;
		this.hasShot = false;
		this.hasFought = false;
		this.passedChargeTest = false;
		this.passedBrokenTest = false;
		this.tempTerrifying = isTerrifying;
		this.isTransfixed = false;
		this.hasUsedMagic = false;
		this.supporting = null;
		this.supporters = new ArrayList<Unit>();
		this.hasRetreated = true;
		
		//Unique to Deadly Shot rule
		this.shotsFired = 0;
		
		for (Equipment e : this.equipmentList){
			if (e.options != null)
				e.options.select(0);
		}
		for (Button refreshButton : this.refreshButtons) {
			refreshButton.dispatchEvent(new MouseEvent(refreshButton, MouseEvent.MOUSE_CLICKED, 
					System.currentTimeMillis(), 0, 10, 10, 1, false));
		}
		this.refreshButtons.clear();
	}	
	public void shootAt(Unit target) {
		// Ensure we're allowed to shoot
		if (Utils.inchDist(this, target) > this.shootRange 
				|| this.moveLeft < this.move * this.moveNeededToShoot
				|| this.battle != null
				|| (target.battle != null && this.armyIndex == Game.GOODINDEX)
				|| this.shotsFired >= 3) {
			if (Utils.inchDist(this, target) > this.shootRange)
				UI.messageLog.add("Too far away!");
			else if (this.moveLeft < this.move * this.moveNeededToShoot)
				UI.messageLog.add("Already moved too far this turn, can't shoot");
			else if (this.battle != null)
				UI.messageLog.add("In a fight, can't shoot");
			else if (target.battle != null && this.armyIndex == Game.GOODINDEX)
				UI.messageLog.add("Good units can't shoot into fights");
			else if (this.shotsFired >= 3)
				UI.messageLog.add("Already shot full amount");
			else if (this.layingDown)
				UI.messageLog.add("Can't shoot while laying down");
			else if (!this.canSee(target))
				UI.messageLog.add("Can't see the target!");
			((ShootUI)game.myUI.phaseUI).setShooting(false);
			game.myUI.repaint();
			return;
		}
		
		// Check for vision/get number of obstacles
		ArrayList<Terrain> losBlockers = new ArrayList<Terrain>();
		ArrayList<Unit> losUnits = new ArrayList<Unit>();
		for(Terrain t : game.board.terrainList) {
			int losBlock = t.blocksLOS(this, target);
			if(losBlock == Terrain.FULLY_BLOCKED){
				UI.messageLog.add("Blocked by an obstacle");
				((ShootUI)game.myUI.phaseUI).setShooting(false);
				game.myUI.repaint();
				return;
			}
			else if(losBlock == Terrain.PARTIAL_BLOCKED &&
					!terrainContacted.contains(t)) {
				losBlockers.add(t);
			}
		}
		
		final Legolas thisUnit = this;
		
		ActionListener normalShot = new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				
				class CustomComp implements Comparator<Terrain>{
					public Unit shooter;
					public Unit target;
					public CustomComp(Unit shooter, Unit target) {
						this.shooter = shooter;
						this.target = target;
					}
					public int compare(Terrain t1, Terrain t2) {
						Point2D t1Point = t1.contactPoint(shooter.x, shooter.y, target.x, target.y, shooter.pixelRadius);
						Point2D t2Point = t2.contactPoint(shooter.x, shooter.y, target.x, target.y, shooter.pixelRadius);
						return (int)Math.round(Utils.pixelDist(t1Point.getX(), t1Point.getY(), shooter.x, shooter.y) -
								Utils.pixelDist(t2Point.getX(), t2Point.getY(), shooter.x, shooter.y));
					}
				}
				CustomComp myTComp = new CustomComp(thisUnit,target);
				Collections.sort(losBlockers, myTComp);
				
				for(Army a : game.armies){
					for(Unit unit : a.units){
						if (unit != thisUnit && unit != target && unit.blocksLOS(thisUnit, target)
								&& !thisUnit.unitsContacted.contains(unit)) {
							losUnits.add(unit);
						}
					}
				}
				class CustomCompU implements Comparator<Unit>{
					public Unit shooter;
					public CustomCompU(Unit shooter) {
						this.shooter = shooter;
					}
					public int compare(Unit u1, Unit u2) {
						return (int)Math.round(Utils.pixelDist(u1.x, u1.y, shooter.x, shooter.y) -
								Utils.pixelDist(u2.x, u2.y, shooter.x, shooter.y));
					}
				}
				CustomCompU myUComp = new CustomCompU(thisUnit);
				Collections.sort(losUnits, myUComp);
				// If you're a good guy, you can't shoot past own units.
				if(thisUnit.armyIndex == Game.GOODINDEX){
					for(Unit unit : losUnits) {
						if (unit.armyIndex == thisUnit.armyIndex) {
							UI.messageLog.add("Good units can't shoot with own units partially blocking");
							((ShootUI)game.myUI.phaseUI).setShooting(false);
							game.myUI.repaint();
							return;
						}
					}
				}
				
				if (losUnits.size() == 0)
					UI.messageLog.add(thisUnit.toChoiceString() + " is shooting at " + target.toChoiceString() + " with " + 
									losBlockers.size() + " obstacles");
				else 
					UI.messageLog.add(thisUnit.toChoiceString() + " is shooting at " + target.toChoiceString() + " with " + 
							losBlockers.size() + " obstacles and " + losUnits.size() + " units in the way");
				thisUnit.shotsFired += 1;
				if (thisUnit.shotsFired >= 3)
					thisUnit.hasShot = true;
				
				thisUnit.shootForHit(target, losBlockers, losUnits);
			}
		};
		
		ActionListener deadlyShot = new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				UI.messageLog.add(toChoiceString() + " is using Deadly Shot, automatic hit");
				thisUnit.shotsFired += 3;
				thisUnit.hasShot = true;
				thisUnit.shootForWound(target);
			}
		};
		
		Button normalButton = new Button("Normal shot");
		Button deadlyButton = new Button("Deadly shot");
		
		if (this.shotsFired > 0) {
			normalButton.addActionListener(normalShot);
			normalButton.dispatchEvent(new ActionEvent(normalButton, ActionEvent.ACTION_PERFORMED, "Normal Shot"));
		}
		else {
			game.myUI.storeVisibleComponents();
			game.myUI.disableComponents();
			
			normalButton.setBounds(game.myUI.dim.width-100, 0, 100, 100);
			deadlyButton.setBounds(game.myUI.dim.width-100, 100, 100, 100);
			
			normalButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					game.myUI.remove(normalButton);
					game.myUI.remove(deadlyButton);
					game.myUI.reenableComponents();
				}
			});
			normalButton.addActionListener(normalShot);
			deadlyButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					game.myUI.remove(normalButton);
					game.myUI.remove(deadlyButton);
					game.myUI.reenableComponents();
				}
			});
			deadlyButton.addActionListener(deadlyShot);
			
			game.myUI.add(normalButton);
			game.myUI.add(deadlyButton);
		}		
	}

}
